﻿// Copyright (c) 2008 screamingtarget@gmail.com

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.


using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;

using NfoViewer.Properties;

namespace NfoViewer
{
   internal class File
   {
      public DateTime LastModified
      {
         get { return System.IO.File.GetLastWriteTime( FullPath ); }
      }

      public string FullPath
      {
         get { return Path.GetFullPath( _fileName ); }
      }

      public string FileName
      {
         get { return Path.GetFileName( _fileName ); }
      }

      public Image Image
      {
         get { return GetAssociatedImage(); }
      }

      public string[] Lines
      {
         get { return _lines.ToArray(); }
      }

      public int Size
      {
         get { return _size; }
      }

      public File( string fileName, string conversion )
      {
         _fileName = fileName;
         _conversion = conversion;
      }

      public bool Load()
      {
         bool success = false;

         _size = 0;

         _lines.Clear();

         StringBuilder line = new StringBuilder();

         using ( FileStream fs = new FileStream( FullPath, FileMode.Open,
            FileAccess.Read ) )
         {
            _size = (int)fs.Length;

            using ( BinaryReader reader = new BinaryReader( fs ) )
            {
               bool lastCharCR = false;
               bool lastTwoCharsCR = false;
               bool lastCharLF = false;

               byte[] bytes = reader.ReadBytes( Size );

               int index = 0;

               while ( index < bytes.Length )
               {
                  byte current = bytes[ index ];

                  if ( current == CARRIAGE_RETURN )
                  {
                     // I found a whacked NFO file that used <CR><CR><LF> so
                     // I'll handle it (and another that used <LF><CR>)
                     //
                     if ( lastCharLF )
                     {
                        lastCharLF = false;
                     }
                     else if ( lastTwoCharsCR )
                     {
                        _lines.Add( Environment.NewLine );
                        _lines.Add( Environment.NewLine );
                        lastCharCR = true;
                        lastTwoCharsCR = false;
                     }
                     else if ( lastCharCR )
                     {
                        lastTwoCharsCR = true;
                     }
                     else
                     {
                        lastCharCR = true;
                        _lines.Add( line.ToString() );
                        line.Length = 0;
                     }
                  }
                  else if ( current == LINE_FEED )
                  {
                     if ( lastTwoCharsCR )
                     {
                        lastTwoCharsCR = false;
                     }
                     else if ( !lastCharCR )
                     {
                        _lines.Add( line.ToString() );
                        line.Length = 0;
                     }

                     lastCharCR = false;
                     lastCharLF = true;
                  }
                  else if ( current == TAB )
                  {
                     line.Append( "    " );
                     lastCharCR = false;
                     lastTwoCharsCR = false;
                     lastCharLF = false;
                  }
                  //else if ( current == 32 )
                  //{
                  //   line.Append( Convert.ToChar( 0xA0 ) );
                  //   lastCharCR = false;
                  //   lastTwoCharsCR = false;
                  //   lastCharLF = false;
                  //}
                  else if ( current >= 32 )
                  {
                     line.Append( _conversion[ current - 32 ] );
                     lastCharCR = false;
                     lastTwoCharsCR = false;
                     lastCharLF = false;
                  }
                  else
                  {
                     line.Append( Resources.NonPrintingChar );
                     lastCharCR = false;
                     lastTwoCharsCR = false;
                     lastCharLF = false;
                  }

                  ++index;
               }

               _lines.Add( line.ToString() );

               success = true;
            }
         }
         
         return success;
      }

      [SuppressMessage( "Microsoft.Security",
         "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands" )]
      private Image GetAssociatedImage()
      {
         NativeMethods.SHFILEINFO shinfo = new NativeMethods.SHFILEINFO();

         IntPtr hIconSmall = NativeMethods.SHGetFileInfo( FullPath, 0,
            ref shinfo, (uint)Marshal.SizeOf( shinfo ),
            NativeMethods.SHGFI_ICON | NativeMethods.SHGFI_SMALLICON );

         if ( hIconSmall != IntPtr.Zero )
         {
            Bitmap bmp = Icon.FromHandle( shinfo.hIcon ).ToBitmap();
            NativeMethods.DestroyIcon( shinfo.hIcon );
            return bmp;
         }

         return Properties.Resources.DefaultDoc;
      }

      private const byte LINE_FEED = 0x0A;
      private const byte CARRIAGE_RETURN = 0x0D;
      private const byte TAB = 0x09;

      private string _fileName;
      private string _conversion;

      private List<string> _lines = new List<string>();
      private int _size;
   }
}
